﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using TP2.Lib;
using TP2.XNA_Game.Vistas;
using Microsoft.Xna.Framework.Graphics;
using System.Reflection;
using Microsoft.Xna.Framework;

namespace TP2.XNA_Game
{
    public static class Controlador
    {

        /// <summary>
        ///Actualiza la posicion de las vistas.
        /// </summary>
        /// <param name="listaVistas"></param>
        /// <param name="ImagenExplosion"></param>
        internal static void ActualizarVistas(IEnumerable<IVista> listaVistas, Texture2D ImagenExplosion)          
        {                
            foreach (Vista vista in listaVistas)              
            {

                vista.Actualizar();                  
                if (!vista.ElementoJuegoAsociado.EstoyVivo())      
                {                     
                    vista.CambiarImagenAExplosion(ImagenExplosion);           
                }             
            }          
        }


        /// <summary>
        /// Elimina de la lista de objetos dibujables los elementos sin vida.
        /// </summary>
        /// <param name="ListaVistasVehiculos"></param>
        /// <param name="ListaVistasArmas"></param>
        internal static void FiltrarVistasMuertas(List<IVista> ListaVistasVehiculos, List<IVista> ListaVistasArmas)
        {
            if (ListaVistasArmas.Count != 0)
            {
                FiltrarVistas(ListaVistasArmas);
            }

            if (ListaVistasVehiculos.Count != 0)
            {
                FiltrarVistas(ListaVistasVehiculos);
            }
        }

        /// <summary>
        /// Elimina de la lista aquellas vistas cuyo elemento del modelo asociado haya muerto.
        /// </summary>
        /// <param name="listaVistas"></param>
        internal static void FiltrarVistas(List<IVista> listaVistas)
        {

            for (int index = listaVistas.Count - 1; index >= 0; index--)
            {
                ///Si el elemento No esta vivo lo elimino
                if (!((Vista)listaVistas.ElementAt(index)).ElementoJuegoAsociado.EstoyVivo())
                {
                    listaVistas.RemoveAt(index);
                }
            }
        }

        /// <summary>
        /// Elimina en su totalidad la lista de elementos
        /// </summary>
        /// <param name="elementosJuego"></param>
        internal static void VaciarListaElementosJuego(List<ElementoJuego> elementosJuego)
        {
            for (int index = elementosJuego.Count - 1; index >= 0; index--)
            {
                elementosJuego.RemoveAt(index);                
            }

        }

        /// <summary>
        /// Si existen elementos de antes los elimina
        /// </summary>
        /// <param name="listaVistas"></param>
        internal static void VaciarVistas(List<IVista> listaVistas)
        {

            if (listaVistas.Count != 0)
            {
                for (int index = listaVistas.Count - 1; index >= 0; index--)
                {
                    listaVistas.Remove(((Vista)listaVistas[index]));
                }
            }
        }

        /// <summary>
        /// Hace un analisis de los proyectiles utilizando reflexion para crear vistas generadas por los Veiculos Aereos.
        /// </summary>
        /// <param name="misionX"></param>
        /// <param name="DiccionarioLaser"></param>
        /// <param name="ListaVistasArmas"></param>
        /// <param name="ImagenLaser"></param>
        /// <param name="ImagenCohete"></param>
        /// <param name="ImagenTorpedoSimple"></param>
        /// <param name="ImagenTorpedoRastreador"></param>
        /// <param name="ImagenLanzaLaser"></param>
        /// <param name="ImagenLanzaCohete"></param>
        /// <param name="ImagenLanzaTorpedoSimple"></param>
        /// <param name="ImagenLanzaTorpedoRastreador"></param>
        /// <param name="ImagenTanqueEnergia"></param>
        internal static void ProcesarProyectiles(Mision misionX, Dictionary<Laser, VistaLaser> DiccionarioLaser, List<IVista> ListaVistasArmas,
                                              Texture2D ImagenLaser, Texture2D ImagenCohete, Texture2D ImagenTorpedoSimple, Texture2D ImagenTorpedoRastreador, Texture2D ImagenLanzaLaser, Texture2D ImagenLanzaCohete, Texture2D ImagenLanzaTorpedoSimple, Texture2D ImagenLanzaTorpedoRastreador, Texture2D ImagenTanqueEnergia)
        {
            if (misionX.ArmasVoladorasEnemigas.Count != 0)
            {
                foreach (Proyectil proyectil in misionX.ArmasVoladorasEnemigas)
                {
                    if (proyectil is Laser)//Agrego este IF porque Cuando se trata del bombardero o caza q dispara otra cosa q no es laser, el casteo falla porque no puede castear ni un cohete ni un torpedo a Laser
                    {
                        if (!DiccionarioLaser.ContainsKey((Laser)proyectil))
                        {
                            ///Uso de Reflexion
                            IVista vistaProyectil = ObtenerVista(proyectil);
                            ///Metodo auxiliar para setear la Imagen a cada elemento.
                            SetImagen((Vista)vistaProyectil, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador,ImagenLanzaLaser,ImagenLanzaCohete,ImagenLanzaTorpedoSimple,ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                            DiccionarioLaser.Add((Laser)proyectil, (VistaLaser)vistaProyectil);
                            ListaVistasArmas.Add(vistaProyectil);
                        }
                    }
                    else // esto hace lo mismo q se hace arriba, entonces porque evaluamos la condicion del diccionario si igualmente vamos a hacer las 3 lineas siguientes?
                    {
                        IVista vistaProyectil = ObtenerVista(proyectil);
                        ///Metodo auxiliar para setear la Imagen a cada elemento.
                        SetImagen((Vista)vistaProyectil, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador,ImagenLanzaLaser,ImagenLanzaCohete,ImagenLanzaTorpedoSimple,ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                        ListaVistasArmas.Add(vistaProyectil);
                    }
                }
            }
        }


        /// <summary>
        /// Hace un analisis de los elementos Estaticos utilizando reflexion para crear vistas generadas por los Veiculos Aereos.
        /// </summary>
        /// <param name="misionX"></param>
        /// <param name="DiccionarioLanzaLaser"></param>
        /// <param name="DiccionarioLanzaCohete"></param>
        /// <param name="DiccionarioLanzaTorpedoSimple"></param>
        /// <param name="DiccionarioLanzaTorpedoRastreador"></param>
        /// <param name="DiccionarioTanqueEnergia"></param>
        /// <param name="ListaVistasArmas"></param>
        /// <param name="ImagenLaser"></param>
        /// <param name="ImagenCohete"></param>
        /// <param name="ImagenTorpedoSimple"></param>
        /// <param name="ImagenTorpedoRastreador"></param>
        /// <param name="ImagenLanzaLaser"></param>
        /// <param name="ImagenLanzaCohete"></param>
        /// <param name="ImagenLanzaTorpedoSimple"></param>
        /// <param name="ImagenLanzaTorpedoRastreador"></param>
        /// <param name="ImagenTanqueEnergia"></param>
        internal static void ProcesarEstaticos(Mision misionX, Dictionary<LanzaLaser, VistaLanzaLaser> DiccionarioLanzaLaser, Dictionary<LanzaCohete, VistaLanzaCohete> DiccionarioLanzaCohete, Dictionary<LanzaTorpedoSimple, VistaLanzaTorpedoSimple> DiccionarioLanzaTorpedoSimple, Dictionary<LanzaTorpedoRastreador, VistaLanzaTorpedoRastreador> DiccionarioLanzaTorpedoRastreador, Dictionary<TanqueEnergia, VistaTanqueEnergia> DiccionarioTanqueEnergia, List<IVista> ListaVistasArmas,
                                      Texture2D ImagenLaser, Texture2D ImagenCohete, Texture2D ImagenTorpedoSimple, Texture2D ImagenTorpedoRastreador, Texture2D ImagenLanzaLaser, Texture2D ImagenLanzaCohete, Texture2D ImagenLanzaTorpedoSimple, Texture2D ImagenLanzaTorpedoRastreador, Texture2D ImagenTanqueEnergia)
        {
            if (misionX.ElementosEstaticos.Count != 0)
            {
                foreach (ElementoJuego elemento in misionX.ElementosEstaticos)
                {
                    if (elemento is Arma)//Agrego este IF porque Cuando se trata del bombardero o caza q dispara otra cosa q no es laser, el casteo falla porque no puede castear ni un cohete ni un torpedo a Laser
                    {
                        if (elemento is LanzaLaser)//Tiene que ir por tema de casteo en tiempo de ejecucion
                        {
                            if (!DiccionarioLanzaLaser.ContainsKey((LanzaLaser)elemento))
                            {
                                IVista vistaArma = ObtenerVista(elemento);
                                SetImagen((Vista)vistaArma, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador, ImagenLanzaLaser, ImagenLanzaCohete, ImagenLanzaTorpedoSimple, ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                                DiccionarioLanzaLaser.Add((LanzaLaser)elemento, (VistaLanzaLaser)vistaArma);
                                ListaVistasArmas.Add(vistaArma);
                            }
                        }

                        if (elemento is LanzaCohete) //Tiene que ir por tema de casteo en tiempo de ejecucion
                        {
                            if (!DiccionarioLanzaCohete.ContainsKey((LanzaCohete)elemento))
                            {
                                IVista vistaArma = ObtenerVista(elemento);
                                SetImagen((Vista)vistaArma, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador, ImagenLanzaLaser, ImagenLanzaCohete, ImagenLanzaTorpedoSimple, ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                                DiccionarioLanzaCohete.Add((LanzaCohete)elemento, (VistaLanzaCohete)vistaArma);
                                ListaVistasArmas.Add(vistaArma);
                            }
                        }

                        if (elemento is LanzaTorpedoSimple)
                        {
                            if (!DiccionarioLanzaTorpedoSimple.ContainsKey((LanzaTorpedoSimple)elemento))
                            {
                                IVista vistaArma = ObtenerVista(elemento);
                                SetImagen((Vista)vistaArma, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador, ImagenLanzaLaser, ImagenLanzaCohete, ImagenLanzaTorpedoSimple, ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                                DiccionarioLanzaTorpedoSimple.Add((LanzaTorpedoSimple)elemento, (VistaLanzaTorpedoSimple)vistaArma);
                                ListaVistasArmas.Add(vistaArma);
                            }
                        }

                        if (elemento is LanzaTorpedoRastreador)
                        {
                            if (!DiccionarioLanzaTorpedoRastreador.ContainsKey((LanzaTorpedoRastreador)elemento))
                            {
                                IVista vistaArma = ObtenerVista(elemento);
                                SetImagen((Vista)vistaArma, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador, ImagenLanzaLaser, ImagenLanzaCohete, ImagenLanzaTorpedoSimple, ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                                DiccionarioLanzaTorpedoRastreador.Add((LanzaTorpedoRastreador)elemento, (VistaLanzaTorpedoRastreador)vistaArma);
                                ListaVistasArmas.Add(vistaArma);
                            }
                        }

                    }
                    if (elemento is TanqueEnergia) // esto hace lo mismo q se hace arriba, entonces porque evaluamos la condicion del diccionario si igualmente vamos a hacer las 3 lineas siguientes?
                    {
                        if (!DiccionarioTanqueEnergia.ContainsKey((TanqueEnergia)elemento))
                        {
                            IVista vistaTanque = ObtenerVista(elemento);
                            ///Metodo auxiliar para setear la Imagen a cada elemento.
                            SetImagen((Vista)vistaTanque, ImagenLaser, ImagenCohete, ImagenTorpedoSimple, ImagenTorpedoRastreador, ImagenLanzaLaser, ImagenLanzaCohete, ImagenLanzaTorpedoSimple, ImagenLanzaTorpedoRastreador, ImagenTanqueEnergia);
                            DiccionarioTanqueEnergia.Add((TanqueEnergia)elemento, (VistaTanqueEnergia)vistaTanque);
                            ListaVistasArmas.Add(vistaTanque);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Metodo que procesa la accion de las armas del Jugador
        /// </summary>
        /// <param name="misionX"></param>
        /// <param name="ListaVistasArmas"></param>
        /// <param name="vistaAlgo42"></param>
        /// <param name="ImagenLaser"></param>
        /// <param name="ImagenCohete"></param>
        /// <param name="ImagenTorpedoSimple"></param>
        /// <param name="ImagenTorpedoRastreador"></param>
        internal static void ProcesarInput(Mision misionX, List<IVista> ListaVistasArmas, VistaAlgo42 vistaAlgo42,
                                        Texture2D ImagenLaser, Texture2D ImagenCohete, Texture2D ImagenTorpedoSimple, Texture2D ImagenTorpedoRastreador)
        {
            EvaluarPresionarTeclaW(misionX, ListaVistasArmas, vistaAlgo42, ImagenLaser);
            EvaluarPresionarTeclaS(misionX, ListaVistasArmas, vistaAlgo42, ImagenCohete);
            EvaluarPresionarTeclaD(misionX, ListaVistasArmas, vistaAlgo42, ImagenTorpedoSimple);
            EvaluarPresionarTeclaA(misionX, ListaVistasArmas, vistaAlgo42, ImagenTorpedoRastreador);
        }
       
      
       internal static void RangosElementosEnemigos(List<IVista> ListaVistasVehiculos, GraphicsDeviceManager graphics)
        {
            foreach (Vista vista in ListaVistasVehiculos)
            {
                vista.RangosElemento(graphics);
            }
        }

       #region ----- Metodos Privados --------


       /// <summary>
       /// Metodo que utiliza refleccion para crear una vista.
       /// </summary>
       /// <param name="elemento"></param>
       /// <returns></returns>
       private static IVista ObtenerVista(ElementoJuego elemento)
       {

           Type tipoVista = Assembly
               .GetExecutingAssembly()
               .GetTypes()
               .Where(type => type.Implements<IVista>())
               .Where(type => type.HasAttribute<VistaParaAttribute>())
               .Where(type => type.GetAttribute<VistaParaAttribute>().TipoEntidad == elemento.GetType())
               .First();
           return tipoVista.CreateInstance<IVista>(new object[] { elemento }); // Problema con la imagen como se que vista es para asociarle la imagen. { , imagen}

       }
       /// <summary>
       /// Setea la imagen correspondiente a la vista en cuestion.
       /// </summary>
       /// <param name="algunaVista"></param>
       /// <param name="ImagenLaser"></param>
       /// <param name="ImagenCohete"></param>
       /// <param name="ImagenTorpedoSimple"></param>
       /// <param name="ImagenTorpedoRastreador"></param>
       /// <param name="ImagenLanzaLaser"></param>
       /// <param name="ImagenLanzaCohete"></param>
       /// <param name="ImagenLanzaTorpedoSimple"></param>
       /// <param name="ImagenLanzaTorpedoRastreador"></param>
       /// <param name="ImagenTanqueEnergia"></param>
       private static void SetImagen(Vista algunaVista, Texture2D ImagenLaser, Texture2D ImagenCohete, Texture2D ImagenTorpedoSimple,
                                      Texture2D ImagenTorpedoRastreador, Texture2D ImagenLanzaLaser, Texture2D ImagenLanzaCohete,
                                      Texture2D ImagenLanzaTorpedoSimple, Texture2D ImagenLanzaTorpedoRastreador, Texture2D ImagenTanqueEnergia)
       {
           if (algunaVista is VistaLaser)
           {
               algunaVista.Default = ImagenLaser;
           }
           else if (algunaVista is VistaCohete)
           {
               algunaVista.Default = ImagenCohete;
           }
           else if (algunaVista is VistaTorpedoSimple)
           {
               algunaVista.Default = ImagenTorpedoSimple;
           }
           else if (algunaVista is VistaTorpedoRastreador)
           {
               algunaVista.Default = ImagenTorpedoRastreador;
           }
           else if (algunaVista is VistaLanzaLaser)
           {
               algunaVista.Default = ImagenLanzaLaser;
           }
           else if (algunaVista is VistaLanzaCohete)
           {
               algunaVista.Default = ImagenLanzaCohete;
           }
           else if (algunaVista is VistaLanzaTorpedoSimple)
           {
               algunaVista.Default = ImagenTorpedoSimple;
           }
           else if (algunaVista is VistaLanzaTorpedoRastreador)
           {
               algunaVista.Default = ImagenLanzaTorpedoRastreador;
           }
           else if (algunaVista is VistaTanqueEnergia)
           {
               algunaVista.Default = ImagenTanqueEnergia;
           }
       }

       /// <summary>
       /// Observa si fue pulsada la tecla "A"
       /// </summary>
       /// <param name="misionX"></param>
       /// <param name="ListaVistasArmas"></param>
       /// <param name="vistaAlgo42"></param>
       /// <param name="ImagenTorpedoRastreador"></param>
       private static void EvaluarPresionarTeclaA(Mision misionX, List<IVista> ListaVistasArmas, VistaAlgo42 vistaAlgo42, Texture2D ImagenTorpedoRastreador)
       {
           if (Keyboard.GetState().IsKeyDown(Keys.A) & vistaAlgo42.ElementoJuegoAsociado.EstoyVivo())
           {
               ///Genero Proyectil TorpedoRastreador
               TorpedoRastreador TorpedoRastreadorAlgo42 = (TorpedoRastreador)((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Disparar(((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Armas.ElementAt(3));
               if (TorpedoRastreadorAlgo42 != null)
               {
                   ///Agrego el Proyectil TorpedoRastreador a la lista del modelo correspondiente.
                   misionX.ArmasVoladorasAliadas.Add(TorpedoRastreadorAlgo42);
                   ///Creo vista
                   VistaTorpedoRastreador vistaTorpedoRastreadorAlgo42 = new VistaTorpedoRastreador(TorpedoRastreadorAlgo42, ImagenTorpedoRastreador);
                   ///Agrego la vista a elementos que voy a Dibujar
                   ListaVistasArmas.Add(vistaTorpedoRastreadorAlgo42);
               }
           }
       }
       /// <summary>
       /// Observa si fue pulsada la tecla "D"
       /// </summary>
       /// <param name="misionX"></param>
       /// <param name="ListaVistasArmas"></param>
       /// <param name="vistaAlgo42"></param>
       /// <param name="ImagenTorpedoSimple"></param>
       private static void EvaluarPresionarTeclaD(Mision misionX, List<IVista> ListaVistasArmas, VistaAlgo42 vistaAlgo42, Texture2D ImagenTorpedoSimple)
       {
           if (Keyboard.GetState().IsKeyDown(Keys.D) & vistaAlgo42.ElementoJuegoAsociado.EstoyVivo())
           {
               ///Genero Proyectil TorpedoSimple
               TorpedoSimple TorpedoSimpleAlgo42 = (TorpedoSimple)((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Disparar(((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Armas.ElementAt(2));
               if (TorpedoSimpleAlgo42 != null)
               {
                   ///Agrego el Proyectil TorpedoSimple a la lista del modelo correspondiente.
                   misionX.ArmasVoladorasAliadas.Add(TorpedoSimpleAlgo42);
                   ///Creo vista
                   VistaTorpedoSimple vistaTorpedoSimpleAlgo42 = new VistaTorpedoSimple(TorpedoSimpleAlgo42, ImagenTorpedoSimple);
                   ///Agrego la vista a elementos que voy a Dibujar
                   ListaVistasArmas.Add(vistaTorpedoSimpleAlgo42);
               }
           }
       }
       /// <summary>
       /// Observa si fue pulsada la tecla "S"
       /// </summary>
       /// <param name="misionX"></param>
       /// <param name="ListaVistasArmas"></param>
       /// <param name="vistaAlgo42"></param>
       /// <param name="ImagenCohete"></param>
       private static void EvaluarPresionarTeclaS(Mision misionX, List<IVista> ListaVistasArmas, VistaAlgo42 vistaAlgo42, Texture2D ImagenCohete)
       {
           if (Keyboard.GetState().IsKeyDown(Keys.S) & vistaAlgo42.ElementoJuegoAsociado.EstoyVivo())
           {
               /*Genero Proyectil Cohete*/
               Cohete CoheteAlgo42 = (Cohete)((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Disparar(((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Armas.ElementAt(1));

               if (CoheteAlgo42 != null)
               {
                   ///Agrego el Proyectil Cohete a la lista del modelo correspondiente.
                   misionX.ArmasVoladorasAliadas.Add(CoheteAlgo42);
                   ///Creo vista
                   VistaCohete vistaCoheteAlgo42 = new VistaCohete(CoheteAlgo42, ImagenCohete);
                   ///Agrego la vista a elementos que voy a Dibujar
                   ListaVistasArmas.Add(vistaCoheteAlgo42);
               }
           }
       }
       /// <summary>
       /// Observa si fue pulsada la tecla "W"
       /// </summary>
       /// <param name="misionX"></param>
       /// <param name="ListaVistasArmas"></param>
       /// <param name="vistaAlgo42"></param>
       /// <param name="ImagenLaser"></param>
       private static void EvaluarPresionarTeclaW(Mision misionX, List<IVista> ListaVistasArmas, VistaAlgo42 vistaAlgo42, Texture2D ImagenLaser)
       {


           if (Keyboard.GetState().IsKeyDown(Keys.W) & vistaAlgo42.ElementoJuegoAsociado.EstoyVivo())
           {
               /*Genero Proyectil Laser*/
               Laser LaserAlgo42 = (Laser)((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Disparar(((AvionJugador)vistaAlgo42.ElementoJuegoAsociado).Armas.ElementAt(0));
               /*Agrego el Proyectil Laser a la lista del modelo correspondiente.*/
               if (LaserAlgo42 != null)
               {
                   misionX.ArmasVoladorasAliadas.Add(LaserAlgo42);
                   /*Creo su vista*/
                   VistaLaser vistaLaserAlgo42 = new VistaLaser(LaserAlgo42, ImagenLaser);

                   //DiccionarioLaser.Add(LaserAlgo42, vistaLaserAlgo42);

                   /*Agrego la vista a lalista elementos que voy a Dibujar*/
                   ListaVistasArmas.Add(vistaLaserAlgo42);
               }
           }
       }

       # endregion 
    }
}
